#include "../sylar/sylar.h"
#include <yaml-cpp/yaml.h>

sylar::ConfigVar<int>::ptr g_int_value_config =
    sylar::Config::Lookup("system.port", (int)8080, "system port");
// sylar::ConfigVar<float>::ptr g_int_value_type_error_config =
//     sylar::Config::Lookup("system.port", (float)80, "system port");
sylar::ConfigVar<float>::ptr f_int_value_config =
    sylar::Config::Lookup("system.floatval", (float)20.2f, "system floatval");

sylar::ConfigVar<std::vector<int>>::ptr g_int_vec_config =
    sylar::Config::Lookup("system.int_vec", std::vector<int>{1, 2}, "system int vector");
sylar::ConfigVar<std::list<int>>::ptr g_int_lis_config =
    sylar::Config::Lookup("system.int_list", std::list<int>{1, 2}, "system int list");
sylar::ConfigVar<std::set<int>>::ptr g_int_set_config =
    sylar::Config::Lookup("system.int_set", std::set<int>{1, 2}, "system int set");
sylar::ConfigVar<std::unordered_set<int>>::ptr g_int_uset_config =
    sylar::Config::Lookup("system.int_uset", std::unordered_set<int>{1, 2}, "system int uset");
sylar::ConfigVar<std::map<std::string, int>>::ptr g_str_int_map_config =
    sylar::Config::Lookup("system.str_int_map", std::map<std::string, int>{{"aa", 1}}, "system int str_int_map");
sylar::ConfigVar<std::unordered_map<std::string, int>>::ptr g_str_int_umap_config =
    sylar::Config::Lookup("system.str_int_umap", std::unordered_map<std::string, int>{{"uaa", 1}}, "system int str_int_umap");
class person
{
public:
    person() {}
    person(int age, const std::string &name, bool sex) : m_age(age), m_name(name), m_sex(sex) {}
    int m_age;
    std::string m_name;
    bool m_sex;
    std::string toString() const
    {
        std::stringstream ss;
        ss << "[person info]" << ":m_age" << m_age << "\nsex:" << m_sex << "\nname: " << m_name << ']';
        return ss.str();
    }
    bool operator==(const person& other_person)const 
    {
        return m_age==other_person.m_age&&m_name==other_person.m_name&& m_sex==other_person.m_sex;

    }
};

namespace sylar
{
    template <>
    class LexicalCast<std::string, person>
    {
    public:
        person operator()(const std::string &str)
        {
            YAML::Node node = YAML::Load(str);
            person tmp;
            tmp.m_name = node["name"].as<std::string>();
            tmp.m_age = node["age"].as<int>();
            tmp.m_sex = node["sex"].as<bool>();
            return tmp;
        }
    };

    template <>
    class LexicalCast<person, std::string>
    {
    public:
        std::string operator()(const person &vec)
        {
            YAML::Node node;
            node["name"] = vec.m_name;
            node["age"] = vec.m_age;
            node["sex"] = vec.m_sex;
            std::stringstream ss;
            ss << node;
            return ss.str();
        }
    };
}
sylar::ConfigVar<person>::ptr g_person_config =
    sylar::Config::Lookup("class.person", person(), "class person");
sylar::ConfigVar<std::map<std::string, person>>::ptr g_str_person_map_config =
    sylar::Config::Lookup("class.map", std::map<std::string, person>{{"kk", person(12, "kk", true)}}, "class person");
sylar::ConfigVar<std::map<std::string, std::vector<person>>>::ptr g_str_person_map_vec_config =
    sylar::Config::Lookup("class.vec_map", std::map<std::string,std::vector<person>>{{"kk", std::vector<person>(2,person(444,"kk",true))}}, "class person");
inline void print_map_person(const std::map<std::string, person> &my_map, const std::string &prefix)
{
    for (auto &i : my_map)
    {
        SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << ": " << prefix << "  " << "{" << i.first << "-" << i.second.toString() << "}" << std::endl;
    }
}
inline void print_map_person(const std::map<std::string, std::vector<person>> &my_map, const std::string &prefix)
{
    for (auto &rr : my_map)
    {
        SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << "map node for person" << ": begin\n"
                                            << "{";
        for (auto &i : rr.second)
        {
            SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << ": " << prefix << "  " << "{" << i.toString() << "}\n"
                                                << std::endl;
        }
        SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << "map node for person" << ": end\n"
                                            << "}";
    }
}
void test_class()
{
    // SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << "before:\n"
    //                                     << g_person_config->toString();
    // print_map_person(g_str_person_map_config->getValue(),"before");
    print_map_person(g_str_person_map_vec_config->getValue(),"before map vec::");
    g_person_config->addListener([](const person& old_one,const person& new_one){
        SYLAR_LOG_INFO(SYLAR_INFO_LOGGER())<<"ooooooooold:::::\n"<<old_one.toString()<<"\n\n\n\n\n"<< new_one.toString()<<"\n";  
    });
    YAML::Node node = YAML::LoadFile("../config/test.yml");
    sylar::Config::LoadFromYaml(node);
    print_map_person(g_str_person_map_vec_config->getValue(),"after map vec::");
    // SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << "after:\n"
    //                                     << g_person_config->getValue().toString();
    // print_map_person(g_str_person_map_config->getValue(),"after");
}
void print_yaml(const YAML::Node &node, int level)
{
    if (node.IsScalar())
    {
        SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << std::string(level * 4, ' ')
                                            << node.Scalar() << " - " << node.Type() << " - " << level;
    }
    else if (node.IsNull())
    {
        SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << std::string(level * 4, ' ')
                                            << "NULL - " << node.Type() << " - " << level;
    }
    else if (node.IsMap())
    {
        for (auto it = node.begin(); it != node.end(); ++it)
        {
            SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << std::string(level * 4, ' ')
                                                << it->first << " - " << it->second.Type() << " - " << level;
            print_yaml(it->second, level + 1);
        }
    }
    else if (node.IsSequence())
    {
        for (size_t i = 0; i < node.size(); ++i)
        {
            SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << std::string(level * 4, ' ')
                                                << i << " - " << node[i].Type() << " - " << level;
            print_yaml(node[i], level + 1);
        }
    }
}
template <class T>
inline void print_info(const T &vec, const std::string &prefix)
{
    SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << ": " << prefix << "  " << vec << std::endl;
}
template <class T>
inline void print_stl(const T &vec, const std::string &prefix)
{
    for (auto &i : vec)
    {
        SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << ": " << prefix << "  " << i << std::endl;
    }
}
template <class T>
inline void print_stl_map(const T &vec, const std::string &prefix)
{
    for (auto &i : vec)
    {
        SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << ": " << prefix << "  " << "{" << i.first << "-" << i.second << "}" << std::endl;
    }
}

void test_yaml()
{
    // {
    //     YAML::Node root = YAML::LoadFile("../config/log.yml");
    //     print_yaml(root, 1);
    SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << "before:\n"
                                        << g_int_value_config->getValue();
    // SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << "before:\n"
    //                                     << f_int_value_config->toString();
    // print_info<float>(g_int_value_type_error_config->getValue(),"float type error before");
    print_stl<std::vector<int>>(g_int_vec_config->getValue(), "vector before");
    print_stl<std::list<int>>(g_int_lis_config->getValue(), "list before");

    print_stl<std::set<int>>(g_int_set_config->getValue(), "set before");
    print_stl<std::unordered_set<int>>(g_int_uset_config->getValue(), "uset before");
    print_stl_map<std::map<std::string, int>>(g_str_int_map_config->getValue(), "str_int_map before");
    print_stl_map<std::unordered_map<std::string, int>>(g_str_int_umap_config->getValue(), "str_int_umap before");
    YAML::Node node = YAML::LoadFile("../config/log.yml");
    sylar::Config::LoadFromYaml(node);
    // print_info<float>(g_int_value_type_error_config->getValue(),"float type error after");
    SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << "after:\n"
                                        << g_int_value_config->getValue() << std::endl;
    print_stl<std::vector<int>>(g_int_vec_config->getValue(), "vector after");
    print_stl<std::list<int>>(g_int_lis_config->getValue(), "list after");

    print_stl<std::set<int>>(g_int_set_config->getValue(), "set after");

    print_stl<std::unordered_set<int>>(g_int_uset_config->getValue(), "uset after");

    print_stl_map<std::map<std::string, int>>(g_str_int_map_config->getValue(), "str_int_map after");
    print_stl_map<std::unordered_map<std::string, int>>(g_str_int_umap_config->getValue(), "str_int_umap after");

    // SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << "after:\n"
    //                                     << f_int_value_config->toString();
}
#include "../sylar/log.h"
#include "../sylar/config.h"
#include "../sylar/util.h"
#include <fstream>
#include <iostream>
#include <string>
#include <cassert>
#include <chrono>
#include <thread>
// 验证日志文件是否包含目标内容
bool checkFileContains(const std::string& filename, const std::string& content) {
    if(filename=="root.log")
    {
        std::cout << filename << "ok ok "<< std::endl;
    }
    std::ifstream file(filename);
    if (!file.is_open()) {
        return false;
    }
    std::string line;
    while (std::getline(file, line)) {
        if (line.find(content) != std::string::npos) {
            return true;
        }
    }
    return false;
}

// 清理测试生成的日志文件
void cleanTestFiles() {
    std::remove("root.log");
    std::remove("system.log");
    std::remove("network.log");
}

// 测试LogAppenderDefine和LogDefine的配置生效
void test_log_appender_config() {
    // 初始化工具和配置
    sylar::InitUtil();
    SYLAR_LOG_INIT();

    // 加载配置文件
    YAML::Node root = YAML::LoadFile("../config/test_define.yml");
    sylar::Config::LoadFromYaml(root);
    auto root_logger = SYLAR_LOG_NAME("root");
    if(root_logger==nullptr)
    {
        std::cerr<< "error root not eixsts\n";
    }
    SYLAR_LOG_INFO(SYLAR_LOG_NAME("root")) << "开始日志配置测试";

    assert(root_logger->getLevel() == sylar::LogLevel::INFO);  // 验证日志级别

    // root日志器不应输出debug级别
    SYLAR_LOG_DEBUG(root_logger) << "root debug message (should not appear)";
    
    // root日志器应输出info级别到文件，warn级别到控制台
    std::string root_info_msg = "root info message";
    SYLAR_LOG_INFO(root_logger) << root_info_msg;
    
    std::string root_warn_msg = "root warn message";
    SYLAR_LOG_WARN(root_logger) << root_warn_msg;

    // 2. 测试system日志器（级别debug）
    auto system_logger = SYLAR_LOG_NAME("system");
    if(system_logger->getLevel() == sylar::LogLevel::DEBUG)
    {
        SYLAR_LOG_INFO(SYLAR_LOGGER())<<"system_logger->getLevel() == sylar::LogLevel::DEBUG\n";
    } // 验证日志级别

    // system日志器应输出debug级别到文件和控制台
    std::string system_debug_msg = "system debug message";
    SYLAR_LOG_INFO(system_logger) << system_debug_msg;
    SYLAR_LOG_WARN(system_logger) << system_debug_msg;

    // 等待日志刷新
    std::this_thread::sleep_for(std::chrono::seconds(2));

    // 3. 验证文件输出
    assert(checkFileContains("root.log", root_info_msg));         // root info应写入文件
    assert(checkFileContains("root.log", root_warn_msg));         // root warn应写入文件
    assert(!checkFileContains("root.log", "root debug message")); // root debug不应写入

    assert(checkFileContains("system.log", system_debug_msg));    // system debug应写入文件

    SS()<< "日志配置测试完成";

    // 清理测试文件
    //cleanTestFiles();
}
void test_toYamlString() {
    // 初始化工具
    sylar::InitUtil();
    SYLAR_LOG_INIT();

    // 1. 创建测试用的日志输出器
    // 文件输出器
    sylar::FileLogAppender::ptr file_appender(new sylar::FileLogAppender("test_to_yaml.log"));
    file_appender->setLevel(sylar::LogLevel::WARN);
    
    // 标准输出器
    sylar::StdoutLogAppender::ptr stdout_appender(new sylar::StdoutLogAppender());
    stdout_appender->setLevel(sylar::LogLevel::INFO);

    // 2. 创建测试日志器并配置
    
    sylar::Logger::ptr test_logger = sylar::LoggerManager::GetInstance()->getLogger("test_yaml_logger");
std::cout << "test_logger名称: " << test_logger->getName() << ", 地址: " << test_logger.get() << std::endl;
    test_logger->setLevel(sylar::LogLevel::DEBUG);
    test_logger->addAppender(file_appender);
    test_logger->addAppender(stdout_appender);

    // 3. 生成YAML字符串
    SYLAR_LOG_INFO(SYLAR_INFO_LOGGER())<<"toYamlString () 前\n";
    std::string yaml_str = test_logger->toYamlString();
    SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << "生成的YAML字符串:\n" << yaml_str;

    // 4. 解析YAML字符串验证内容
    try {
        YAML::Node node = YAML::Load(yaml_str);
        
        // 验证日志器名称
        assert(node["name"].as<std::string>() == "test_yaml_logger");
        
        // 验证日志级别
        assert(node["level"].as<std::string>() == "DEBUG");
        
        // 验证输出器数量
        assert(node["appenders"].size() == 2);

        // 验证第一个输出器（文件输出器）
        YAML::Node file_node = node["appenders"][0];
        assert(file_node["type"].as<std::string>() == "FileLogAppender");
        assert(file_node["file"].as<std::string>() == "test_to_yaml.log");
        assert(file_node["level"].as<std::string>() == "WARN");

        // 验证第二个输出器（标准输出器）
        YAML::Node stdout_node = node["appenders"][1];
        assert(stdout_node["type"].as<std::string>() == "StdoutLogAppender");
        assert(stdout_node["level"].as<std::string>() == "INFO");

    } catch (YAML::Exception& e) {
        SYLAR_LOG_ERROR(SYLAR_LOG_NAME("root")) << "YAML解析失败: " << e.what();
        assert(false); // 解析失败视为测试不通过
    }
    
    SYLAR_LOG_INFO(SYLAR_INFO_LOGGER()) << "toYamlString()测试完成";
}


int main(int argc, char **argv)
{
    // test_yaml();
    //test_class();
    //est_log_inconfig();
    test_log_appender_config();
    //test_logger_config();
    //test_toYamlString();
    return 0;
}